/**
 * Copyright (c) 2008 Trent Hoeppner
 * 
 * This file is part of BillCalc.
 * 
 * BillCalc is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * BillCalc is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with BillCalc.  If not, see <http://www.gnu.org/licenses/>.
 **/

package com.trentech.billcalc.gui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

import testcases.MainTest;

/**
 * DetailView shows details of debts for Residents in an apartment.  The top
 * has a label to describe what is being shown.  The middle area contains 
 * several rows, each with a name and a number.  The bottom has the total for
 * all of the numbers.
 * 
 * @author Trent Hoeppner
 */
public class DetailView extends JPanel {

    /**
     * Required for serialization.
     */
    private static final long serialVersionUID = -3245277308167136867L;
    
    
    /**
     * The label that has a description of what is being shown.
     */
    private JLabel topLabel;
    
    
    /**
     * The container for the name/number pairs.
     */
    private JPanel mainPanel;


    /**
     * The field that contains the total of all the numbers.
     */
    private JTextField totalField;
    
    
    /**
     * The label for {@link #totalField}.
     */
    private JLabel totalLabel;


    /**
     * True if the total field should be used, false otherwise.
     */
    private boolean hasTotalField;
    
    
    /**
     * The values that are used for all rows.
     */
    private List<Integer> values;


    /**
     * Constructor for DetailView.
     * 
     * @param   hasTotalField   true indicates that the values will be 
     *                          tabulated and the total field will be used to 
     *                          display results, false indicates that there 
     *                          the total field is unused.
     */
    public DetailView(boolean hasTotalField) {
        this.hasTotalField = hasTotalField;
        
        setLayout(new BorderLayout());
        
        topLabel = new JLabel();
        add(topLabel, BorderLayout.NORTH);
        
        mainPanel = new JPanel();
        add(mainPanel, BorderLayout.CENTER);
        mainPanel.setLayout(new GridBagLayout());
        
        // original : 
        // if (hasTotalField) {
        // seed fault : 
        if (hasTotalField && (MainTest.isOriginal || MainTest.isFaultFound)) {
        	
            totalLabel = new JLabel(Messages.getString("DetailView.total"));
            totalField = new JTextField();
            totalField.setEditable(false);
            totalField.setHorizontalAlignment(JTextField.RIGHT);
        }
    }
    
    
    /**
     * Sets a new label to be at the top of this.
     * 
     * @param   topLabel    the new label to set.  Cannot be null.
     */
    public void setTopLabel(JLabel topLabel) {
        remove(this.topLabel);
        this.topLabel = topLabel;
        add(topLabel, BorderLayout.NORTH);
    }
    
    
    /**
     * Updates the top label, middle name/number pairs, and the bottom total.
     * 
     * @param   topText     the text to put in the top label.  Cannot be null.
     * @param   newLabels   the labels for each row.  Cannot be null.
     * @param   newValues   the numbers to put in each row.  Cannot be null, 
     *                      and must have the same number of items as newLabels.
     */
    public void setValues(String topText, List<String> newLabels, List<Integer> newValues) {
        topLabel.setText(topText);
        values = newValues;
        
        if (hasTotalField) {
            calcAndSetTotal();
        }

        List<JLabel> labels = new ArrayList<JLabel>();
        List<JComponent> components = new ArrayList<JComponent>();
        int i = 0;
        for (String name : newLabels) {
            JLabel label = new JLabel(name);
            labels.add(label);
            int number = newValues.get(i);
            JTextField value = new JTextField(EventEditor.formatMoneyForDisplay(number));
            value.setEditable(false);
            value.setHorizontalAlignment(JTextField.RIGHT);
            components.add(value);
            i++;
        }
        
        setComponents(labels, components);
    }
    
    
    /**
     * Returns the components that are displayed in tabular form, including the
     * total field if it exists.  The last component will be an empty JLabel
     * that is used to take up empty space on the y axis.
     * 
     * @return  the components in the tabular form.  Will not be null.
     */
    public Component[] getDetailComponents() {
        return mainPanel.getComponents();
    }
    
    
    /**
     * Sets the labels and matching components in this.
     * 
     * @param   labels      the labels to set which will be in the first 
     *                      column.  Cannot be null.
     * @param   components  the components to set which will be in the second
     *                      column.  Cannot be null.
     */
    public void setComponents(List<JLabel> labels, List<JComponent> components) {
        mainPanel.removeAll();

        GridBagConstraints c = new GridBagConstraints();
        
        // original : 
        // int i = 0;
        // seed fault :
        int i = MainTest.isOriginal || MainTest.isFaultFound ? 0 : 1;
        
        for (JLabel label : labels) {
            mainPanel.add(label, createConstraints(c, true, i));
            JComponent value = components.get(i);
            mainPanel.add(value, createConstraints(c, false, i));
            i++;
        }

        // to occupy space at the bottom
        c = createConstraints(c, true, i);
        c.weighty = 1;
        mainPanel.add(new JLabel(""), c);
        
        if (hasTotalField) {
            mainPanel.add(totalLabel, createConstraints(c, true, i + 1));
            mainPanel.add(totalField, createConstraints(c, false, i + 1));
        }
        
        validate();
        repaint();
    }
    
    
    /**
     * Creates a GridBagConstraints for use in the tabular form.  The given 
     * constraints object must have just been created, or just been used to 
     * add an object to a container (default values will be set after adding to 
     * a container).
     * 
     * @param   c       the reset constraints to use.  Cannot be null.
     * @param   label   true if the constraints are for the label, false 
     *                  otherwise.
     * @param   row     the row number (0-based) that the component should be 
     *                  placed in.  Must be >= 0.
     *                  
     * @return  the object that was passed in with modified values.  Will not 
     *          be null.
     */
    private GridBagConstraints createConstraints(GridBagConstraints c, boolean label, int row) {
        if (label) {
            c.fill = GridBagConstraints.NONE;
            c.gridx = 0;
            c.anchor = GridBagConstraints.LINE_END;
            c.weightx = 0.1;
        }
        else {
            c.fill = GridBagConstraints.HORIZONTAL;
            c.gridx = 1;
            c.anchor = GridBagConstraints.LINE_START;
            c.weightx = 1;
        }
        c.gridy = row;
        c.weighty = 0;
        c.insets = new Insets(2, 2, 2, 2);
        return c;
    }
    
    
    /**
     * Calculates the total of all values and updates the bottom text.
     */
    private void calcAndSetTotal() {
        int total = 0;
        for (int value : values) {
            total += value;
        }
        
        totalField.setText(EventEditor.formatMoneyForDisplay(total));
    }

}
